class Vm
  def initialize(fname)
    begin
      f=open(fname)
    rescue
      abort $!
    end

    @c=[]
    while l=f.gets
      l.chomp!
      if l=~/\Acon\s+(\-?\d+)\z/
        @c << [:con, $~[1].to_i]
      else
        @c << [l]
      end
    end
    @c.freeze

    @s=[]
    @i=0
    @step=@max=0
  end

  def run
    puts '*** START ***'

    while true
      unless l=@c[@i]
        abort 'cannot fetch next instruction'
      end

      case l[0]
      when :con
        con l[1]
      when 'add'
        add
      when 'sub'
        sub
      when 'mul'
        mul
      when 'div'
        div
      when 'god'
        god
      when 'jpo'
        jpo
      when 'gto'
        gto
      when 'pop'
        pop
      when 'pri'
        pri
      when 'red'
        red
      when 'hal'
        break
      else
        abort 'unknown instruction: '+l[0]
      end
      
      @step+=1
      @max=@s.size if @s.size>@max
    end

    puts "*** HALT *** (#{@step} steps, #{@max} stacks)"
  end

  private
  def con(n)
    @s << n
    @i+=1
  end

  def pop
    unless @s.pop
      abort 'pop: stack is empty'
    end
    @i+=1
  end

  def add
    y=@s.pop
    x=@s.pop
    unless x and y
      abort('add: stack is empty')
    end
    @s << x+y
    @i+=1
  end

  def sub
    y=@s.pop
    x=@s.pop
    unless x and y
      abort('sub: stack is empty')
    end
    @s << x-y
    @i+=1
  end

  def mul
    y=@s.pop
    x=@s.pop
    unless x and y
      abort('mul: stack is empty')
    end
    @s << x*y
    @i+=1
  end

  def div
    y=@s.pop
    x=@s.pop
    unless x and y
      abort('div: stack is empty')
    end
    abort 'div: division by zero' if y==0

    q=x/y
    if q>=0 or (x%y).zero?
      @s << q
    else
      @s << q.succ
    end
#    if q>=0
#      @s << q
#    else
#      @s << -(-x/y)
#    end

    @i+=1
  end

  def pri
    if a=@s.pop
      puts a
    else
      abort 'pri: stack is empty'
    end
    @i+=1
  end

  def god
    abort 'god: stack is empty' unless n=@s.pop
    abort 'god: stack out of bounds' unless @s.size>n
    @s << @s[n]
    @i+=1
  end

  def gto
    abort 'gto: stack is empty' unless n=@s.pop
    abort 'gto: stack out of bounds' unless @s.size-1>n
    @s[n]=@s.pop
    @i+=1
  end

  def red
    puts 'input an integer?'
    begin
      t=Integer($stdin.gets.strip)
    rescue ArgumentError
      abort $!
    end
    @s << t
    @i+=1
  end

  def jpo
    abort 'jpo: stack is empty' unless n=@s.pop and k=@s.pop
    abort 'jpo: next instruction is not found' if n>=@c.size

    if k>0
      @i=n
    else
      @i+=1
    end
  end
end

if ARGV.size==0
  fname='epro.code'
elsif ARGV.size==2 and ARGV[0]=='-i'
  fname=ARGV[1]
else
  abort "usage: ruby #{$0} [ -i code ]"
end

Vm.new(fname).run
